package deployr.core;

import static java.text.MessageFormat.*;

import java.io.*;
import java.util.*;

public class WebApp {

	private final Checksum added;

	private final Checksum updated;

	private final Collection<String> removed = new TreeSet<String>();

	private final WebAppCount webAppCount;

	private final String root;

	private ZipListener createdZips = new ZipListener();

	public WebApp(String root, Map<String, String> added, Map<String, String> updated, Collection<String> removed) {
		this.root = root;
		this.added = new Checksum(added);
		this.updated = new Checksum(updated);
		this.removed.addAll(removed);
		webAppCount = new WebAppCount(added.keySet(), updated.keySet(), removed);
	}

	public boolean added(String path) {
		return added.contains(path);
	}

	public int addedCount() {
		return added.size();
	}

	public Checksum addedOrUpdated() {
		return added.merge(updated);
	}

	public int addedOrUpdatedCount() {
		return addedCount() + updatedCount();
	}

	public String checksum() {
		return addedOrUpdated().toString();
	}
	
	public int classesCount() {
		return webAppCount.classesAddedOrUpdated();
	}

	public boolean contains(String path) {
		if (added(path)) return true;
		if (updated(path)) return true;
		if (removed(path)) return true;
		return false;
	}

	public int count(String type) {
		if (type.equals("root")) return webAppCount.rootAddedOrUpdated();
		if (type.equals("classes")) return webAppCount.classesAddedOrUpdated();
		if (type.equals("lib")) return webAppCount.libAddedOrUpdated();
		if (type.equals("webinf")) return webAppCount.webinfAddedOrUpdated();
		return 0;
	}

	public Iterable<String> createdZips() {
		return createdZips;
	}

	public int createdZipsSize() {
		return createdZips.size();
	}

	public String diff() {
		StringBuilder toStringBuilder = new StringBuilder();
		append("+", added, toStringBuilder);
		append("*", updated, toStringBuilder);
		append("-", removed, toStringBuilder);
		return toStringBuilder.toString();
	}

	private void append(String prefix, Iterable<String> files, StringBuilder stringBuilder) {
		for (String path : files) {
			stringBuilder.append(format("{0} {1}\n", prefix, path));
		}
	}

	public WebApp diff(WebApp webapp2) {
		return new WebAppDiff(this, webapp2).webapp();
	}

	public int filesCount() {
		return addedCount() + updatedCount() + removedCount();
	}

	public int libCount() {
		return webAppCount.libAddedOrUpdated();
	}

	public void remove(String string) {
		removed.add(string);
	}

	public boolean removed(String string) {
		return removed.contains(string);
	}

	int removedCount() {
		return removed.size();
	}

	public String root() {
		return root;
	}

	public int rootCount() {
		return webAppCount.rootAddedOrUpdated();
	}

	public boolean updated(String path) {
		return updated.contains(path);
	}

	public int updatedCount() {
		return updated.size();
	}

	public int webinfCount() {
		return webAppCount.webinfAddedOrUpdated();
	}

	public void zip(String target) {
		ZipPartitioned zipClasses = new ZipPartitioned(root, addedOrUpdated());
		zipClasses.zip(target);
	}

	public void zip(String target, List<String> addedOrUpdated) {
		ZipPartitioned zip = new ZipPartitioned(root, addedOrUpdated);
		zip.attach(createdZips);
		zip.zip(target);
	}

	public void copy(String target, Iterable<String> addedOrUpdated) {
		Copy copy = new Copy(root, addedOrUpdated);
		copy.attach(createdZips);
		copy.copy(target);
	}

	public void zip(String type, String target) {
		if (type.equals("root")) zip(target, webAppCount.rootAddedOrUpdatedFiles());
		if (type.equals("classes")) zip(target, webAppCount.classesAddedOrUpdatedFiles());
		if (type.equals("lib")) zip(target, webAppCount.libAddedOrUpdatedFiles());
		if (type.equals("webinf")) zip(target, webAppCount.webinfAddedOrUpdatedFiles());
	}

	public void copy(String type, String target) {
		if (type.equals("root")) copy(target, webAppCount.rootAddedOrUpdatedFiles());
		if (type.equals("classes")) copy(target, webAppCount.classesAddedOrUpdatedFiles());
		if (type.equals("lib")) copy(target, webAppCount.libAddedOrUpdatedFiles());
		if (type.equals("webinf")) copy(target, webAppCount.webinfAddedOrUpdatedFiles());
	}

	public void copyTo(File dest) {
		Copy copy = new Copy(root, addedOrUpdated());
		copy.attach(createdZips);
		copy.copy(dest.getAbsolutePath());
	}

	public void zipTo(File dest) {
		Zip zip = new Zip(root, addedOrUpdated());
		zip.attach(createdZips);
		zip.zip(dest.getAbsolutePath());
	}

	public boolean needUpdate() {
		return webAppCount.any() > 0;
	}

}